A programmer writes source code according to a specification directed to the programmer's convenience. A compiler converts source code to machine or object code, which is executable directly by the particular machine environment. Alternatively or in addition, a compiler converts source code to an intermediate representation (“virtual machine code/instructions”), such as bytecode, which is executable by a virtual machine. A virtual machine is capable of running on top of a variety of particular machine environments.
Constant propagation and folding are compile-time processes that help optimize compiled code and thereby reduce the amount of processing needed at runtime. In constant propagation, the compiler identifies expressions that have constant values and substitutes (or “propagates”) the constant values in place of those expressions. As used herein, the term “expression” refers to a source code instruction, or portion thereof, that produces a value. For example, a reference to an initialized variable may be considered an expression. As another example, an arithmetic operation may be considered an expression. Many different types of expressions exist. In constant folding, the compiler identifies an expression that requires evaluation but resolves as a constant, i.e., that returns a constant value given constant input. For example, consider an expression that receives the constant numerical input “3” over a theoretically unlimited number of trials. If the expression always returns the constant string value “three,” the expression resolves as a constant. However, if the expression sometimes returns the constant string value “three” and sometimes returns a different value, the expression does not resolve as a constant. For an expression that resolves as a constant, the compiler evaluates the expression to obtain the constant value and replaces the expression with the constant value. After constant folding, it is no longer necessary to evaluate the expression at runtime. The compiler may also propagate the constant value resulting from constant folding, further improving the efficiency of the compiled code. For ease of discussion, as used herein, the term “input” may refer to input passed to a method or function. Alternatively or in addition, the term “input” may refer to an operand in an expression, such as one side of a multiplication expression. In general, the term “input” may refer to any value (or expression that resolves as a value) upon which the resolved value of an expression depends. An expression that returns a constant value given constant inputs may also be referred to as a “pure” function of its inputs.
The approaches described in this section are approaches that could be pursued, but not necessarily approaches that have been previously conceived or pursued. Therefore, unless otherwise indicated, it should not be assumed that any of the approaches described in this section qualify as prior art merely by virtue of their inclusion in this section.